package comp.comp.wxxcx_login.service;

import java.net.HttpURLConnection;
import java.net.URL;

import java.util.*;
import java.io.*;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import org.apache.commons.httpclient.protocol.Protocol;
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;

import com.alibaba.fastjson.*;

import javax.net.ssl.*;
import java.security.*;

import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;

import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import comp.comp.wxxcx_login.service.MySecureProtocolSocketFactory;

public class Utils {
    private final static Logger logger = LoggerFactory.getLogger(Utils.class);

    private static final TrustManager[] UNQUESTIONING_TRUST_MANAGER = new TrustManager[]{
            new X509TrustManager() {
                public java.security.cert.X509Certificate[] getAcceptedIssuers(){
                    return null;
                }
                public void checkClientTrusted( X509Certificate[] certs, String authType ){}
                public void checkServerTrusted( X509Certificate[] certs, String authType ){}
            }
        };

    public  static void turnOffSslChecking() throws NoSuchAlgorithmException, KeyManagementException {
        final SSLContext sc = SSLContext.getInstance("SSL");
        sc.init( null, UNQUESTIONING_TRUST_MANAGER, null );
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
    }

    public static void turnOnSslChecking() throws KeyManagementException, NoSuchAlgorithmException {
        SSLContext.getInstance("SSL").init( null, null, null );
    }
    
	static {
		//ProtocolSocketFactory fcty = new MySecureProtocolSocketFactory();
		//Protocol.registerProtocol("https", new Protocol("https", fcty, 443));
        try {
            turnOffSslChecking();
        } catch (Exception e) {}
	}

    public static HttpServletRequest GetRequest() {
        ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest req = sra.getRequest();
        return req;
    }
    public static HttpServletResponse GetResponse() {
        ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletResponse resp = sra.getResponse();
        return resp;
    }
    
    public static String GatewayUrl() {
        if (System.getProperty("GATEWAY_SERVICEADDRESS") != null)
            return "http://" + System.getProperty("GATEWAY_SERVICEADDRESS") + ":" + System.getProperty("GATEWAY_PORT");
        logger.info("===GATEWAY_SERVICEADDRESS is not specified, use domain name");
        return GetAppUrl();
    }
    
    public static String GetAppUrl() {
         ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest req = sra.getRequest();
       StringBuilder sb = new StringBuilder(128);
        sb.append(req.getScheme()).append("://").append(req.getServerName());
        if (req.getServerPort() != 80)
            sb.append(":").append(req.getServerPort());
        return sb.toString();
    }

    public static String GetAppIdFromReferer() {
        String referer = Utils.GetRequest().getHeader("Referer");
        int start = referer.indexOf("/", 10);
        int end = referer.indexOf("/", start + 1);
        return referer.substring(start + 1, end);
    }

    public static Boolean IsCallFromH5() {
        // https://servicewechat.com/{appid}/{version}/page-frame.html
        String referer = Utils.GetRequest().getHeader("Referer");
        int start = referer.indexOf("://", 3);
        int end = referer.indexOf("/", start + 5);
        String serverName = referer.substring(start + 3, end);

        logger.info("===getServerName:" + serverName);
        /*
        Enumeration<String> temp = Utils.GetRequest().getHeaderNames();
        while(temp.hasMoreElements()){
            String val = temp.nextElement();
            logger.info("===header:" + val);
            logger.info("====value:" + Utils.GetRequest().getHeader(val));
        }
        */
        return !serverName.equals("servicewechat.com");
    }

    /*
     miniapp  小程序, cp 企业号(企业微信), mp 公众号
     web 网站应用, app 移动应用, weibo , qq 
     */
    public static String GetAppId(String type) throws Exception {
        if ("miniapp".equals(type)) {
            if (!IsCallFromH5()) {
                return GetAppIdFromReferer();
            }
        } else if ("mp".equals(type) || "open".equals(type)) {
            String url= GatewayUrl() + "/config/config/configs/search/like?key=com.qq.weixin.mp.appID";
            if ("open".equals(type))
                url= GatewayUrl() + "/config/config/configs/search/like?key=com.qq.weixin.open.appID";
            String ret = Utils.GET(url, false);
            if (ret != null) {
                JSONArray arr = JSON.parseArray(ret);
                if (arr.size() > 0) {
                    return ((JSONObject)arr.get(0)).getString("fvalue");
                }
            }
        }
        return "";
    }

    public static String ReadBody(HttpServletRequest req)
    {
        BufferedReader reader = null;
        StringBuilder sb = new StringBuilder(1024);
        try {
            reader = req.getReader();
            String str;
            while ((str = reader.readLine()) != null)
                sb.append(str);
            reader.close();
        } catch (IOException e) {
            logger.error("===Error when read body", e);
        } finally {
            if (null != reader) {
                try {
                    reader.close();
                } catch (IOException e) {
                    logger.error("===Error when close reader", e);
                }
            }
        }
        return sb.toString();
    }
 
    public static String GET(String url, boolean withCookie) throws Exception {
        RestTemplate restTemplate = new RestTemplate();
        HttpHeaders headers = new HttpHeaders();
        MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
        headers.setContentType(type);
        headers.add("Accept", MediaType.APPLICATION_JSON.toString());
        if (Utils.GetRequest().getHeader("Referer") != null)
            headers.add("Referer", Utils.GetRequest().getHeader("Referer"));
        if (withCookie && Utils.GetRequest().getHeader("Cookie") != null)
            headers.add("Cookie", Utils.GetRequest().getHeader("Cookie"));
        logger.info("===set headers:Referer:{}, Cookie:{}",  Utils.GetRequest().getHeader("Referer"),  Utils.GetRequest().getHeader("Cookie"));
        HttpEntity<String> reqEntity = new HttpEntity<String>(headers);

        ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, reqEntity, String.class);
        int statusCode = response.getStatusCodeValue();
        String ret = response.getBody();
        logger.info("===HTTPGET(" + url + ")=" + ret);
        return ret;
    }
   
    public static ResponseEntity<String> POST_JSON(String url, Map<String, String> map, String data, boolean withCookie) throws Exception {
        RestTemplate restTemplate = new RestTemplate();
        HttpHeaders headers = new HttpHeaders();
        MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
        headers.setContentType(type);
        headers.add("Accept", MediaType.APPLICATION_JSON.toString());
        if (Utils.GetRequest().getHeader("Referer") != null)
            headers.add("Referer", Utils.GetRequest().getHeader("Referer"));
        if ((map == null || !map.containsKey("Cookie")) && withCookie && Utils.GetRequest().getHeader("Cookie") != null)
            headers.add("Cookie", Utils.GetRequest().getHeader("Cookie"));
        if (map != null) {
            for (String key : map.keySet()) {
                headers.add(key, map.get(key));
            }
        }
        logger.info("===set headers:Referer:{}, Cookie:{}",  headers.get("Referer"),  headers.get("Cookie"));

        HttpEntity<String> reqEntity = new HttpEntity<String>(data, headers);
        return restTemplate.exchange(url, HttpMethod.POST, reqEntity, String.class);
    }

    public static ResponseEntity<String> POST_FORM(String url, Map<String, String> map, MultiValueMap<String, String> post, boolean withCookie) throws Exception {
        RestTemplate restTemplate = new RestTemplate();
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        headers.add("Accept", MediaType.APPLICATION_JSON.toString());
        if (Utils.GetRequest().getHeader("Referer") != null)
            headers.add("Referer", Utils.GetRequest().getHeader("Referer"));
        if ((map == null || !map.containsKey("Cookie")) && withCookie && Utils.GetRequest().getHeader("Cookie") != null)
            headers.add("Cookie", Utils.GetRequest().getHeader("Cookie"));
        if (map != null) {
            for (String key : map.keySet()) {
                headers.add(key, map.get(key));
            }
        }
        logger.info("===set headers:Referer:{}, Cookie:{}",  headers.get("Referer"),  headers.get("Cookie"));
        HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<MultiValueMap<String, String>>(post, headers);
    
        return restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
    }

    public static JSONObject Request(String urlString, String method, Map<String, String> map, String jsonData, boolean withCookie) {
        try {
            logger.info("===Request(" + urlString + ", " + method + ", " + jsonData + ")");
            URL url = new URL(urlString);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod(method);
            conn.setRequestProperty("Content-Type", "application/json; charset=utf-8");
            if (Utils.GetRequest().getHeader("Referer") != null)
                conn.setRequestProperty("Referer", Utils.GetRequest().getHeader("Referer"));
            if (withCookie && Utils.GetRequest().getHeader("Cookie") != null)
                conn.setRequestProperty("Cookie", Utils.GetRequest().getHeader("Cookie"));
            if (map != null) {
                for (String key : map.keySet()) {
                    conn.setRequestProperty(key, map.get(key));
                }
            }

            conn.setDoInput(true);

            if (jsonData != null) {
                conn.setDoOutput(true);
                OutputStream stream = conn.getOutputStream();
                stream.write(jsonData.getBytes());
                stream.flush();
                stream.close();
            }

            JSONObject obj = new JSONObject();
            int responseCode = conn.getResponseCode();
            obj.put("responseCode", responseCode);
            logger.info("===Response code: " + responseCode);

            if (responseCode == 204 || responseCode == 404) {
                obj.put("responseData", "");
                return obj;
            }
            InputStream stream = null;
            if (responseCode >= 400)
                stream = conn.getErrorStream();
            else
                stream = conn.getInputStream();

            StringBuffer sb = new StringBuffer();
            int len = 0;
            while (true) {
                byte[] b = new byte[1024];
                len = stream.read(b);
                if (len < 0)
                    break;
                sb.append(new String(b, 0, len));
            }
            stream.close();
            conn.disconnect();
            String responseData = sb.toString().trim();
            obj.put("responseData", responseData);

            logger.info("===Response data:");
            logger.info(responseData);
            return obj;
        } catch (Exception e) {
            logger.error("===Request({}, {}, {}) error: {}", urlString, method, jsonData, e.getMessage());
        }
        return null;
    }
}

